package com.thoughtworks.impersonator.http.replay;

import static com.thoughtworks.impersonator.http.IntegrationTestUtils.post;
import static com.thoughtworks.impersonator.http.IntegrationTestUtils.startServer;
import static org.junit.Assert.assertEquals;

import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.URL;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.eclipse.jetty.server.Server;
import org.junit.Test;

import com.thoughtworks.impersonator.http.message.RequestIdentifier;
import com.thoughtworks.impersonator.http.record.Recorder;
import com.thoughtworks.impersonator.http.test.FixedUidRequestIdentifier;

public class ImpersonatorTest {

    private static final int SERVER_PORT = 9900;
    private static final int RECORDER_PORT = SERVER_PORT + 1;
    private static final int IMPERSONATOR_PORT = SERVER_PORT + 2;

    @Test
    public void shouldReplayARecordedHttpExchange() throws Exception {
        RequestIdentifier requestIdentifier = new FixedUidRequestIdentifier("w00t");

        Server server = startServer(SERVER_PORT, "w00t");

        Recorder recorder = new Recorder(RECORDER_PORT, "127.0.0.1", SERVER_PORT, new File("target/tmp"),
                requestIdentifier);
        String proxiedResponse = post("http://127.0.0.1:" + RECORDER_PORT, "hot=bubbles");
        recorder.stop();

        server.stop();

        Impersonator impersonator = new Impersonator(IMPERSONATOR_PORT, new File("target/tmp"), requestIdentifier);
        String impersonatedResponse = post("http://127.0.0.1:" + IMPERSONATOR_PORT, "hot=bubbles");
        impersonator.stop();

        assertEquals(proxiedResponse, impersonatedResponse);

    }

    @Test
    public void shouldHandleLargeHtmlFilesCorrectly() throws Exception {
        File storageDir = storageDirFor("large-html.request");
        RequestIdentifier requestIdentifier = new FixedUidRequestIdentifier("large-html");

        Impersonator impersonator = new Impersonator(IMPERSONATOR_PORT, storageDir, requestIdentifier);
        String returned = sendRequestFromFile(new File(storageDir, "large-html.request"));
        impersonator.stop();

        assertEquals(withoutHeaders(returned), withoutHeaders(getResponseBody(storageDir)));
    }

    private String sendRequestFromFile(File file) throws IOException, UnsupportedEncodingException {
        final Socket socket = new Socket();
        socket.connect(new InetSocketAddress("127.0.0.1", IMPERSONATOR_PORT));
        BufferedWriter wr = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF8"));
        wr.write(FileUtils.readFileToString(file));
        wr.flush();
        String returned = IOUtils.toString(socket.getInputStream(), "utf-8");
        socket.close();
        return returned;
    }

    private File storageDirFor(String file) {
        URL resource = getClass().getClassLoader().getResource(file);
        File path = new File(resource.getFile());
        return path.getParentFile();
    }

    private String withoutHeaders(String body) {
        return body.substring(body.indexOf("<!DOCTYPE"));
    }

    private String getResponseBody(File storageDir) throws IOException {
        return FileUtils.readFileToString(new File(storageDir, "large-html.response"), "utf-8");
    }

}
